home *** CD-ROM | disk | FTP | other *** search
- NAME
- perlsec - Perl security
-
- DESCRIPTION
- Perl is designed to make it easy to write secure setuid
- and setgid scripts. Unlike shells, which are based on
- multiple substitution passes on each line of the script,
- Perl uses a more conventional evaluation scheme with fewer
- hidden "gotchas". Additionally, since the language has
- more built-in functionality, it has to rely less upon
- external (and possibly untrustworthy) programs to
- accomplish its purposes.
-
- Beyond the obvious problems that stem from giving special
- privileges to such flexible systems as scripts, on many
- operating systems, setuid scripts are inherently insecure
- right from the start. This is because that between the
- time that the kernel opens up the file to see what to run,
- and when the now setuid interpreter it ran turns around
- and reopens the file so it can interpret it, things may
- have changed, especially if you have symbolic links on
- your system.
-
- Fortunately, sometimes this kernel "feature" can be
- disabled. Unfortunately, there are two ways to disable
- it. The system can simply outlaw scripts with the setuid
- bit set, which doesn't help much. Alternately, it can
- simply ignore the setuid bit on scripts. If the latter is
- true, Perl can emulate the setuid and setgid mechanism
- when it notices the otherwise useless setuid/gid bits on
- Perl scripts. It does this via a special executable
- called suidperl that is automatically invoked for you if
- it's needed.
-
- If, however, the kernel setuid script feature isn't
- disabled, Perl will complain loudly that your setuid
- script is insecure. You'll need to either disable the
- kernel setuid script feature, or put a C wrapper around
- the script. See the program wrapsuid in the eg directory
- of your Perl distribution for how to go about doing this.
-
- There are some systems on which setuid scripts are free of
- this inherent security bug. For example, recent releases
- of Solaris are like this. On such systems, when the
- kernel passes the name of the setuid script to open to the
- interpreter, rather than using a pathname subject to
- mettling, it instead passes /dev/fd/3. This is a special
- file already opened on the script, so that there can be no
- race condition for evil scripts to exploit. On these
- systems, Perl should be compiled with
- -DSETUID_SCRIPTS_ARE_SECURE_NOW. The Configure program
- that builds Perl tries to figure this out for itself.
-
- When executing a setuid script, or when you have turned on
- taint checking explicitly using the -T flag, Perl takes
- special precautions to prevent you from falling into any
- obvious traps. (In some ways, a Perl script is more
- secure than the corresponding C program.) Any command
- line argument, environment variable, or input is marked as
- "tainted", and may not be used, directly or indirectly, in
- any command that invokes a subshell, or in any command
- that modifies files, directories, or processes. Any
- variable that is set within an expression that has
- previously referenced a tainted value also becomes tainted
- (even if it is logically impossible for the tainted value
- to influence the variable). For example:
-
- $foo = shift; # $foo is tainted
- $bar = $foo,'bar'; # $bar is also tainted
- $xxx = <>; # Tainted
- $path = $ENV{'PATH'}; # Tainted, but see below
- $abc = 'abc'; # Not tainted
-
- system "echo $foo"; # Insecure
- system "/bin/echo", $foo; # Secure (doesn't use sh)
- system "echo $bar"; # Insecure
- system "echo $abc"; # Insecure until PATH set
-
- $ENV{'PATH'} = '/bin:/usr/bin';
- $ENV{'IFS'} = '' if $ENV{'IFS'} ne '';
-
- $path = $ENV{'PATH'}; # Not tainted
- system "echo $abc"; # Is secure now!
-
- open(FOO,"$foo"); # OK
- open(FOO,">$foo"); # Not OK
-
- open(FOO,"echo $foo|"); # Not OK, but...
- open(FOO,"-|") || exec 'echo', $foo; # OK
-
- $zzz = `echo $foo`; # Insecure, zzz tainted
-
- unlink $abc,$foo; # Insecure
- umask $foo; # Insecure
-
- exec "echo $foo"; # Insecure
- exec "echo", $foo; # Secure (doesn't use sh)
- exec "sh", '-c', $foo; # Considered secure, alas
-
- The taintedness is associated with each scalar value, so
- some elements of an array can be tainted, and others not.
-
- If you try to do something insecure, you will get a fatal
- error saying something like "Insecure dependency" or
- "Insecure PATH". Note that you can still write an
- insecure system call or exec, but only by explicitly doing
- something like the last example above. You can also
- bypass the tainting mechanism by referencing
- subpatterns--Perl presumes that if you reference a
- substring using $1, $2, etc, you knew what you were doing
- when you wrote the pattern:
-
- $ARGV[0] =~ /^-P(\w+)$/;
- $printer = $1; # Not tainted
-
- This is fairly secure since \w+ doesn't match shell
- metacharacters. Use of /.+/ would have been insecure, but
- Perl doesn't check for that, so you must be careful with
- your patterns. This is the ONLY mechanism for untainting
- user supplied filenames if you want to do file operations
- on them (unless you make $> equal to $< ).
-
- For "Insecure $ENV{PATH}" messages, you need to set
- $ENV{'PATH'} to a known value, and each directory in the
- path must be non-writable by the world. A frequently
- voiced gripe is that you can get this message even if the
- pathname to an executable is fully qualified. But Perl
- can't know that the executable in question isn't going to
- execute some other program depending on the PATH.
-
- It's also possible to get into trouble with other
- operations that don't care whether they use tainted
- values. Make judicious use of the file tests in dealing
- with any user-supplied filenames. When possible, do opens
- and such after setting $> = $<. (Remember group IDs,
- too!) Perl doesn't prevent you from opening tainted
- filenames for reading, so be careful what you print out.
- The tainting mechanism is intended to prevent stupid
- mistakes, not to remove the need for thought.
-
- This gives us a reasonably safe way to open a file or
- pipe: just reset the id set to the original IDs. Here's a
- way to do backticks reasonably safely. Notice how the
- exec() is not called with a string that the shell could
- expand. By the time we get to the exec(), tainting is
- turned off, however, so be careful what you call and what
- you pass it.
-
- die unless defined $pid = open(KID, "-|");
- if ($pid) { # parent
- while (<KID>) {
- # do something
- }
- close KID;
- } else {
- $> = $<;
- $) = $(; # BUG: initgroups() not called
- exec 'program', 'arg1', 'arg2';
- die "can't exec program: $!";
- }
-
- For those even more concerned about safety, see the Safe
- and Safe CGI modules at a CPAN site near you. See the
- perlmod manpage for a list of CPAN sites.
-